<?php

class grades_report {
	
	/**
	 * Код класса (all|a|b|c|класс)
	 * @var string
	 */
	private $class_code = NULL;
	
	/**
	 * Код отчета
	 * @var string
	 */
	private $report_code = NULL;
	
	/**
	 * Код курса
	 * @var string
	 */
	private $course_code = NULL;
	
	function __construct($class_code, $report_code, $course_code) {
		global $CFG;
		include_once($CFG->app_dir . '/grade/class.grades.php');
		$this->set_class_code($class_code);
		$this->set_report_code($report_code);
		$this->set_course_code($course_code);
	}
	
	function __destruct() {
		
	}
	
	function set_class_code($class_code) {
		$this->class_code = $class_code;
	}
	
	function set_report_code($report_code) {
		$this->report_code = $report_code;
	}
	
	function set_course_code($course_code) {
		$this->course_code = $course_code;
	}
	
	private function add_pupils($report) {
		$result = array();
		// Добавление учеников
		foreach ($report as $class_name => $class) {
			$i = 0;
			foreach ($class['pupils'] as $pupil) {
				$result[$class_name]['pupils'][$i]['pupil'] = $pupil['pupil'];
				$result[$class_name]['courses'] = array();
				$result[$class_name]['pupils'][$i++]['grades'] = array();
			}
		}
		return $result;
	}
	
	/**
	 * Добавляет отчет в общий отчет
	 * @param array $result Общий отчет
	 * @param array $report Отчет, который нужно добавить в общий
	 * @param string $add_to_initials Добавка к инициалам
	 */
	private function add_report($result, $report, $add_to_initials = '') {
		// Добавление экзамена в результирующий массив
		foreach ($report as $class_name => $class) {
			// переименовываем инициалы курса
			foreach ($class['courses'] as $initials) {
				$result[$class_name]['courses'][] = $initials . $add_to_initials;
			}
			$result[$class_name]['count'][] = count($class['courses']);
			$i = 0;
			foreach ($class['pupils'] as $pupil) {
				foreach ($pupil['grades'] as $grade) {
					$result[$class_name]['pupils'][$i]['grades'][] = $grade;
				}
				$i++;
			}
		}
		return $result;
	}
	
	/**
	 * Меняет местами значения в массиве по ключам
	 */
	private function swap(&$array, $key_1, $key_2) {
		$tmp = $array[$key_1];
		$array[$key_1] = $array[$key_2];
		$array[$key_2] = $tmp;
	}
	
	/**
	 * Генерирует общую ведомость из нескольких простых
	 * @param array of (strings | arrays) $grades_codes Массив кодов оценок или уже готовых массивов с оценками
	 * @param array $initials Инициалы, которые нужно добавить к названию столбика с оценкой
	 */
	private function generate_combined_report($grades_codes, $initials = NULL) {
		// Собирание отчета по частям
		// Обрабока уже готовых массивов с оценками
		$part_report = array();
		for ($i = 0; is_array($grades_codes[$i]); $i++) {
			$part_report[] = $grades_codes[$i];
		}
		
		// Если коды оценок еще остались
		if (isset($grades_codes[$i])) {
			// Инициализация кода оценки
			$grades = new grades(
				$this->class_code,
				$grades_codes[$i++],
				$this->course_code
			);
			// добавление части отчета
			$part_report[] = $grades->get_grades();
			
			for (; $i < count($grades_codes); $i++) {
				// инициализация новой части, если очередной элемент - это код оценки
				if (is_string($grades_codes[$i])) {
					$grades->set_itemname($grades_codes[$i]);
					$part_report[] = $grades->get_grades();
				} else {
					// если не код оценки, а уже готовый массив
					$part_report[] = $grades_codes[$i];
				}
			}
		}
		
		// Сборка отчета
		// Формирование информации об учениках
		$result = $this->add_pupils($part_report[0]);
		// формирование информации об оценках
		for ($i = 0; $i < count($part_report); $i++) {
			if (isset($initials)) { // добавление инициалов, если требуется
				$result = $this->add_report($result, $part_report[$i], $initials[$i]);
			} else {
				$result = $this->add_report($result, $part_report[$i]);
			}
		}
		return $result;
	}
	
	/**
	 * Сортирует оценки в экзаменационной ведомости
	 * @param array $report Отчет с оценками
	 */
	private function exam_sort($report) {
		foreach ($report as $class_name => &$class) {
			// Формирование шаблона по которому будет идти сортировка
			$courses_initials = $class['courses'];
			sort($courses_initials);
			
			// Обмен местами оценок
			for ($i = 0; $i < count($courses_initials); $i++) {
				// если не совпадает порядок колонок с требуемым, то поменять их
				if ($class['courses'][$i] != $courses_initials[$i]) {
					$old_position = array_search($courses_initials[$i], $class['courses']);
					$this->swap($class['courses'], $old_position, $i);
					// и у каждого ученика =)
					foreach ($class['pupils'] as &$pupil) {
						$this->swap($pupil['grades'], $old_position, $i);
					}
					unset($pupil);
				}
			}
		}
		unset($class);
		return $report;
	}
	
	/**
	 * Отчет по экзаменам
	 * @param string $semester Код семестра (римские цифры)
	 */
	private function get_exam_report($semester) {
		$result = $this->generate_combined_report(
			array('WE'.$semester, 'VE'.$semester, 'E'.$semester), 
			array('П', 'У', '')
		);
		return $this->exam_sort($result);
	}
	
	/**
	 * Все месячные баллы I семестра
	 */
	private function get_all_month_report_I() {
		return $this->generate_combined_report(
			array('09', '10', '12')
		);
	}
	
	/**
	 * Итоговая ведомость I семестр
	 */
	private function get_final_report_I() {
		return $this->generate_combined_report(
			array('PI', $this->get_exam_report('I'), 'I')
		);
	}
	
	/**
	 * Все месячные баллы II семестра
	 */
	private function get_all_month_report_II() {
		return $this->generate_combined_report(
			array('02', '03', '04', '05')
		);
	}
	
	/**
	 * Итоговая ведомость II семестр
	 */
	private function get_final_report_II() {
		return $this->generate_combined_report(
			array('PII', $this->get_exam_report('II'), 'II')
		);
	}
	
	/**
	 * Все оценки за год
	 */
	private function get_final_report_Y() {
		return $this->generate_combined_report(
			array(
				'09', '10', '12', 
				'PI', $this->get_exam_report('I'), 'I', 
				'02', '03', '04', '05',
				'PII',$this->get_exam_report('II'), 'II'
			)
		);
	}
	
	function get_previous_year_report() {
		include_once(__DIR__ . '/class.grades_previous_year.php');
		
		$grades = new grades_previous_year(
			$this->class_code, 
			$this->report_code,
			$this->course_code
		);
		return $grades->get_grades();
	}
	
	private function get_simple_report() {
		$grades = new grades(
			$this->class_code, 
			$this->report_code,
			$this->course_code
		);
		return $grades->get_grades();
	}
	
	/**
	 * Возвращает тип отчета по его коду
	 */
	function get_report_type() {
		$conformity = array(
			'09' => 'simple',
			'10' => 'simple',
			'12' => 'simple',
			'PI' => 'simple',
			'EI' => 'simple',
			'I' => 'simple',
			'AMI' => 'total',
			'FRI' => 'total',
			'02' => 'simple',
			'03' => 'simple',
			'04' => 'simple',
			'05' => 'simple',
			'PII' => 'simple',
			'EII' => 'simple',
			'II' => 'simple',
			'AMII' => 'total',
			'FRII' => 'total',
			'Y' => 'simple',
			'FRY' => 'total'
		);
		return (isset($conformity[$this->report_code])) ? $conformity[$this->report_code] : 'simple';
	}
	
	function get_report() {
		$result = array();
		$result['service_information'] = array('type' => $this->get_report_type(), 'report_code' => $this->report_code); // служебная информация
		
		if ($this->report_code == 'EI') {
			$result['data'] = $this->get_exam_report('I');
		} else if ($this->report_code == 'AMI') {
			$result['data'] = $this->get_all_month_report_I();
		} else if ($this->report_code == 'FRI') {
			$result['data'] = $this->get_final_report_I();
		} else if ($this->report_code == 'EII') {
			$result['data'] = $this->get_exam_report('II');
		} else if ($this->report_code == 'AMII') {
			$result['data'] = $this->get_all_month_report_II();
		} else if ($this->report_code == 'FRII') {
			$result['data'] = $this->get_final_report_II();
		} else if ($this->report_code == 'FRY') {
			$result['data'] = $this->get_final_report_Y();
		} else if ($this->report_code == 'prev_year') {
			$result['data'] = $this->get_previous_year_report();
		} else {
			$result['data'] = $this->get_simple_report();
		}
		
		return $result;
	}
}

?>
